<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>工时统计系统</title>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">

</head>

<body>
    <div class="container">
        <header>
            <button class="theme-toggle" id="themeToggle">
                <i class="fas fa-moon"></i>
            </button>
            <h1><i class="fas fa-business-time"></i> 工时统计系统</h1>
            <p class="subtitle">记录每日上下班时间，自动计算工时和考勤统计（每个日期支持上班/下班时间输入）</p>
        </header>

        <div class="main-content">
            <div class="calendar-section">
                <div class="calendar-container">
                    <div class="month-container">
                        <div class="title-container">
                            <div class="title-button" id="preButton">
                                <i class="fas fa-chevron-left"></i>

                            </div>
                            <div class="month-title" id="monthTitle"></div>
                            <div class="title-button" id="nextButton">
                                <i class="fas fa-chevron-right"></i>

                            </div>

                        </div>
                        <table id="calendar"></table>
                    </div>
                </div>
            </div>

            <div class="stats-section">
                <div class="stat-card">
                    <h2><i class="fas fa-chart-line"></i> 本月工时统计</h2>
                    <div class="stat-value" id="avg-hours">0.0</div>
                    <div class="stat-desc">平均每日工时 (小时)</div>

                    <div class="chart-controls">
                        <div class="chart-zoom-controls">
                            <button class="chart-control-btn" id="zoomOut">
                                <i class="fas fa-search-minus"></i>
                            </button>
                            <button class="chart-control-btn" id="zoomIn">
                                <i class="fas fa-search-plus"></i>
                            </button>
                            <button class="chart-control-btn" id="zoomReset">
                                <i class="fas fa-sync-alt"></i>
                            </button>
                        </div>
                        <div class="chart-scroll-controls">
                            <button class="chart-control-btn" id="scrollLeft">
                                <i class="fas fa-arrow-left"></i>
                            </button>
                            <button class="chart-control-btn" id="scrollRight">
                                <i class="fas fa-arrow-right"></i>
                            </button>
                        </div>
                    </div>
                    <div class="chart-container" id="hours-chart">
                        <div class="chart-bars-container" id="chart-bars">
                            <!-- 图表将由JS动态生成 -->
                        </div>
                    </div>
                </div>

                <div class="stat-card">
                    <h2><i class="fas fa-calendar-alt"></i> 本月考勤概况</h2>
                    <div style="display: flex; justify-content: space-around; margin-top: 30px;">
                        <div style="text-align: center;">
                            <div style="font-size: 2.2rem; color: var(--accent-color); font-weight: 700;"
                                id="recorded-days">0</div>
                            <div style="color: var(--text-secondary);">已记录天数</div>
                        </div>
                        <div style="text-align: center;">
                            <div style="font-size: 2.2rem; color: var(--accent-color); font-weight: 700;"
                                id="total-hours">0.0</div>
                            <div style="color: var(--text-secondary);">总工时</div>
                        </div>
                    </div>

                    <div style="margin-top: 40px; display: flex; justify-content: space-around;">
                        <div style="text-align: center;">
                            <div style="font-size: 1.8rem; color: var(--work-hour-good); font-weight: 700;"
                                id="avg-start">--:--</div>
                            <div style="color: var(--text-secondary);">平均上班时间</div>
                        </div>
                        <div style="text-align: center;">
                            <div style="font-size: 1.8rem; color: var(--work-hour-good); font-weight: 700;"
                                id="avg-end">--:--</div>
                            <div style="color: var(--text-secondary);">平均下班时间</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <footer>
            <p>考勤管理系统 &copy; 2025 | 数据存储在本地浏览器中 | 双击日期可清除时间记录</p>
        </footer>
    </div>

    <script>
        // 获取DOM元素
        const themeToggleBtn = document.getElementById('themeToggle');
        const avgHoursDisplay = document.getElementById('avg-hours');
        const recordedDaysDisplay = document.getElementById('recorded-days');
        const totalHoursDisplay = document.getElementById('total-hours');
        const avgStartDisplay = document.getElementById('avg-start');
        const avgEndDisplay = document.getElementById('avg-end');
        const monthTitle = document.getElementById('monthTitle');
        const chartBarsContainer = document.getElementById('chart-bars');
        const zoomInBtn = document.getElementById('zoomIn');
        const zoomOutBtn = document.getElementById('zoomOut');
        const zoomResetBtn = document.getElementById('zoomReset');
        const scrollLeftBtn = document.getElementById('scrollLeft');
        const scrollRightBtn = document.getElementById('scrollRight');
        const hoursChart = document.getElementById('hours-chart');
        const preButton = document.getElementById('preButton');
        const nextButton = document.getElementById('nextButton');

        // 主题状态
        let isDarkMode = true;
        let isSingleView = true;

        // 月份名称
        const monthNames = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];

        // 存储键名
        const STORAGE_KEY = 'attendanceData';
        const THEME_KEY = 'themePreference';
        const CHART_ZOOM_KEY = 'chartZoomLevel';

        // 图表状态
        let zoomLevel = parseFloat(localStorage.getItem(CHART_ZOOM_KEY)) || 1.0;
        let scrollPosition = 0;
        let maxScroll = 0;

        // 初始化数据存储
        let attendanceData = JSON.parse(localStorage.getItem(STORAGE_KEY)) || {};

        // 初始化主题
        function initTheme() {
            const savedTheme = localStorage.getItem(THEME_KEY);
            if (savedTheme === 'light') {
                document.documentElement.classList.add('light-theme');
                isDarkMode = false;
                themeToggleBtn.innerHTML = '<i class="fas fa-sun"></i>';
            } else {
                document.documentElement.classList.remove('light-theme');
                isDarkMode = true;
                themeToggleBtn.innerHTML = '<i class="fas fa-moon"></i>';
            }
        }

        // 切换主题
        function toggleTheme() {
            if (isDarkMode) {
                document.documentElement.classList.add('light-theme');
                localStorage.setItem(THEME_KEY, 'light');
                themeToggleBtn.innerHTML = '<i class="fas fa-sun"></i>';
            } else {
                document.documentElement.classList.remove('light-theme');
                localStorage.setItem(THEME_KEY, 'dark');
                themeToggleBtn.innerHTML = '<i class="fas fa-moon"></i>';
            }
            isDarkMode = !isDarkMode;
        }

        // 计算每日工时
        function calculateDailyHours(startTime, endTime) {
            if (!startTime || !endTime) return 0;

            const [startHour, startMinute] = startTime.split(':').map(Number);
            const [endHour, endMinute] = endTime.split(':').map(Number);

            const startTotalMinutes = startHour * 60 + startMinute;
            const endTotalMinutes = endHour * 60 + endMinute;

            // 处理跨天情况（如夜班）
            let totalMinutes = endTotalMinutes - startTotalMinutes;
            if (totalMinutes < 0) totalMinutes += 24 * 60;

            // 扣除午休时间（1.5小时）
            totalMinutes = Math.max(0, totalMinutes - 90);

            // 添加晚餐时间扣除逻辑
            if (endTotalMinutes >= 18 * 60) {
                // 下班时间超过18:00，扣除30分钟
                totalMinutes = Math.max(0, totalMinutes - 30);
            } else if (endTotalMinutes >= 17 * 60 + 30 && endTotalMinutes < 18 * 60) {
                // 下班时间在17:30-18:00之间，重新计算到17:30的工时
                const adjustedEndTotalMinutes = 17 * 60 + 30;
                let adjustedMinutes = adjustedEndTotalMinutes - startTotalMinutes;
                if (adjustedMinutes < 0) adjustedMinutes += 24 * 60;
                totalMinutes = Math.max(0, adjustedMinutes - 90);
            }
            // 转换为小时（保留2位小数）
            return parseFloat((totalMinutes / 60).toFixed(2));
        }

        // 将分钟数转换为时间字符串
        function minutesToTime(minutes) {
            const hours = Math.floor(minutes / 60);
            const mins = Math.round(minutes % 60);
            return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}`;
        }

        // 更新统计数据
        function updateStats() {
            const today = new Date();
            const year = today.getFullYear();
            const month = today.getMonth() + 1;

            let recordedDays = 0;
            let totalHours = 0;
            let startTimeSum = 0;
            let endTimeSum = 0;
            const dailyHours = {};

            // 遍历当前月的每一天
            const daysInMonth = new Date(year, month, 0).getDate();
            for (let day = 1; day <= daysInMonth; day++) {
                const dateStr = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
                const record = attendanceData[dateStr];

                if (record && record.startTime && record.endTime) {
                    recordedDays++;
                    const hours = calculateDailyHours(record.startTime, record.endTime);
                    totalHours += hours;
                    dailyHours[day] = hours;

                    // 计算平均上班时间
                    const [startHour, startMinute] = record.startTime.split(':').map(Number);
                    startTimeSum += startHour * 60 + startMinute;

                    // 计算平均下班时间
                    const [endHour, endMinute] = record.endTime.split(':').map(Number);
                    endTimeSum += endHour * 60 + endMinute;
                }
            }

            // 更新统计显示
            recordedDaysDisplay.textContent = recordedDays;
            totalHoursDisplay.textContent = totalHours.toFixed(2);
            avgHoursDisplay.textContent = recordedDays > 0 ? (totalHours / recordedDays).toFixed(2) : '0.00';

            // 更新平均时间
            avgStartDisplay.textContent = recordedDays > 0 ? minutesToTime(startTimeSum / recordedDays) : '--:--';
            avgEndDisplay.textContent = recordedDays > 0 ? minutesToTime(endTimeSum / recordedDays) : '--:--';

            // 更新图表
            updateChart(dailyHours, daysInMonth);
        }

        // 更新图表
        function updateChart(dailyHours, daysInMonth) {
            chartBarsContainer.innerHTML = '';

            // 计算最大工时值用于缩放
            const maxHours = Math.max(8, ...Object.values(dailyHours));

            // 设置图表容器的总宽度
            const barCount = daysInMonth;
            const barWidth = 20 * zoomLevel;
            const gap = 8 * zoomLevel;
            const containerWidth = barCount * (barWidth + gap);
            chartBarsContainer.style.width = `${containerWidth}px`;
            chartBarsContainer.style.gap = `${gap}px`;

            // 计算最大滚动范围
            maxScroll = containerWidth - hoursChart.offsetWidth + 30;

            // 应用当前滚动位置
            chartBarsContainer.style.transform = `translateX(-${scrollPosition}px)`;

            for (let day = 1; day <= daysInMonth; day++) {
                const hours = dailyHours[day] || 0;
                const barHeight = hours > 0 ? (hours / maxHours * 180) : 5; // 最小高度为5px

                const bar = document.createElement('div');
                bar.className = 'chart-bar';
                bar.style.height = `${barHeight}px`;
                bar.style.minWidth = `${barWidth}px`;
                bar.style.flex = `0 0 ${barWidth}px`;

                const label = document.createElement('div');
                label.className = 'chart-label';
                label.textContent = `${day}`;

                // 添加悬浮提示
                bar.title = `${day}日: ${hours.toFixed(1)}小时`;

                bar.appendChild(label);
                chartBarsContainer.appendChild(bar);
            }
        }

        // 保存数据到localStorage
        function saveData(dateStr, startTime, endTime) {
            attendanceData[dateStr] = { startTime, endTime };
            localStorage.setItem(STORAGE_KEY, JSON.stringify(attendanceData));
            updateStats();
        }

        // 清除日期数据
        function clearDateData(dateStr) {
            if (attendanceData[dateStr]) {
                delete attendanceData[dateStr];
                localStorage.setItem(STORAGE_KEY, JSON.stringify(attendanceData));
                updateStats();
                return true;
            }
            return false;
        }

        // 调整图表缩放
        function adjustZoom(amount) {
            const newZoom = Math.max(0.5, Math.min(zoomLevel + amount, 3.0));
            if (newZoom !== zoomLevel) {
                zoomLevel = newZoom;
                localStorage.setItem(CHART_ZOOM_KEY, zoomLevel.toString());
                updateStats();
            }
        }

        // 重置图表缩放
        function resetZoom() {
            zoomLevel = 1.0;
            localStorage.setItem(CHART_ZOOM_KEY, zoomLevel.toString());
            updateStats();
        }

        // 滚动图表
        function scrollChart(direction) {
            const scrollAmount = 100;
            if (direction === 'left') {
                scrollPosition = Math.max(0, scrollPosition - scrollAmount);
            } else {
                scrollPosition = Math.min(maxScroll, scrollPosition + scrollAmount);
            }
            chartBarsContainer.style.transform = `translateX(-${scrollPosition}px)`;
        }

        // 处理鼠标滚轮事件
        function handleMouseWheel(e) {
            // 检查是否按住了Ctrl键
            if (e.ctrlKey) {
                e.preventDefault();
                const delta = Math.sign(e.deltaY) * -0.1;
                adjustZoom(delta);
            } else if (e.shiftKey) {
                // Shift + 滚轮水平滚动
                e.preventDefault();
                scrollPosition = Math.max(0, Math.min(maxScroll, scrollPosition - e.deltaY));
                chartBarsContainer.style.transform = `translateX(-${scrollPosition}px)`;
            }
        }

        // 切换主题
        themeToggleBtn.addEventListener('click', toggleTheme);

        // 图表缩放控制
        zoomInBtn.addEventListener('click', () => adjustZoom(0.1));
        zoomOutBtn.addEventListener('click', () => adjustZoom(-0.1));
        zoomResetBtn.addEventListener('click', resetZoom);
        scrollLeftBtn.addEventListener('click', () => scrollChart('left'));
        scrollRightBtn.addEventListener('click', () => scrollChart('right'));

        // 添加鼠标滚轮事件监听
        hoursChart.addEventListener('wheel', handleMouseWheel, { passive: false });

        // 日历类
        function Calendar(year, month, parent) {
            this.year = year;
            this.month = month;
            this.parent = parent;
            this._init();
        }

        Calendar.prototype._init = function () {
            this.parent.innerHTML = '';
            const today = new Date();
            const isCurrentMonth = (today.getFullYear() === this.year && today.getMonth() === this.month);
            const todayDate = isCurrentMonth ? today.getDate() : 0;

            // 表头
            const thead = document.createElement('thead');
            const trHead = document.createElement('tr');
            const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
            weekDays.forEach(day => {
                const th = document.createElement('th');
                th.textContent = day;
                trHead.appendChild(th);
            });
            thead.appendChild(trHead);
            this.parent.appendChild(thead);

            // 表体
            const tbody = document.createElement('tbody');
            const { daysInMonth, startDay } = this.getMonthData(this.year, this.month);

            let date = 1;
            for (let week = 0; week < 6; week++) {
                const tr = document.createElement('tr');
                for (let day = 0; day < 7; day++) {
                    const td = document.createElement('td');
                    if (day === 0 || day === 6) {
                        td.classList.add('weekend');
                    }

                    if (date === todayDate && isCurrentMonth) {
                        td.classList.add('today');
                    }

                    if (week === 0 && day < startDay || date > daysInMonth) {
                        tr.appendChild(td);
                    } else {
                        const dateStr = `${this.year}-${this.month.toString().padStart(2, '0')}-${date.toString().padStart(2, '0')}`;
                        const record = attendanceData[dateStr];

                        const dateNum = document.createElement('div');
                        dateNum.className = 'date-num';
                        dateNum.textContent = date;
                        td.appendChild(dateNum);

                        // 添加上班时间输入框
                        const startInput = document.createElement('input');
                        startInput.type = 'time';
                        startInput.dataset.date = dateStr;
                        startInput.dataset.type = 'start';

                        if (record && record.startTime) {
                            startInput.value = record.startTime;
                        }

                        // 添加下班时间输入框
                        const endInput = document.createElement('input');
                        endInput.type = 'time';
                        endInput.dataset.date = dateStr;
                        endInput.dataset.type = 'end';

                        if (record && record.endTime) {
                            endInput.value = record.endTime;
                        }

                        // 添加工时显示
                        const hourDisplay = document.createElement('div');
                        hourDisplay.className = 'work-hour-display';

                        if (record && record.startTime && record.endTime) {
                            const hours = calculateDailyHours(record.startTime, record.endTime);
                            hourDisplay.textContent = `${hours.toFixed(2)}小时`;

                            // 根据工时长度设置不同颜色
                            if (hours >= 8.5) {
                                hourDisplay.style.color = 'var(--work-hour-good)';
                            } else if (hours >= 8) {
                                hourDisplay.style.color = 'var(--work-hour-medium)';
                            } else {
                                hourDisplay.style.color = 'var(--work-hour-bad)';
                            }
                        }

                        const timeContainer = document.createElement('div');
                        timeContainer.className = 'time-inputs';

                        timeContainer.appendChild(startInput);
                        timeContainer.appendChild(endInput);
                        timeContainer.appendChild(hourDisplay);

                        td.appendChild(timeContainer);

                        // 添加输入变化事件
                        startInput.addEventListener('change', (e) => {
                            const dateStr = e.target.dataset.date;
                            const startTime = e.target.value;
                            const endInput = td.querySelector('input[data-type="end"]');
                            const endTime = endInput.value;

                            if (startTime && endTime) {
                                const hours = calculateDailyHours(startTime, endTime);
                                hourDisplay.textContent = `${hours.toFixed(2)}小时`;

                                if (hours >= 8.5) {
                                    hourDisplay.style.color = 'var(--work-hour-good)';
                                } else if (hours >= 8) {
                                    hourDisplay.style.color = 'var(--work-hour-medium)';
                                } else {
                                    hourDisplay.style.color = 'var(--work-hour-bad)';
                                }
                            } else {
                                hourDisplay.textContent = '';
                            }

                            saveData(dateStr, startTime, endTime);
                        });

                        endInput.addEventListener('change', (e) => {
                            const dateStr = e.target.dataset.date;
                            const endTime = e.target.value;
                            const startInput = td.querySelector('input[data-type="start"]');
                            const startTime = startInput.value;

                            if (startTime && endTime) {
                                const hours = calculateDailyHours(startTime, endTime);
                                hourDisplay.textContent = `${hours.toFixed(2)}小时`;

                                if (hours >= 8.5) {
                                    hourDisplay.style.color = 'var(--work-hour-good)';
                                } else if (hours >= 8) {
                                    hourDisplay.style.color = 'var(--work-hour-medium)';
                                } else {
                                    hourDisplay.style.color = 'var(--work-hour-bad)';
                                }
                            } else {
                                hourDisplay.textContent = '';
                            }

                            saveData(dateStr, startTime, endTime);
                        });

                        // 添加双击事件清除数据
                        td.addEventListener('dblclick', (e) => {
                            if (e.target.tagName === 'INPUT') return;

                            const dateStr = startInput.dataset.date;
                            if (clearDateData(dateStr)) {
                                startInput.value = '';
                                endInput.value = '';
                                hourDisplay.textContent = '';
                            }
                        });

                        date++;
                        tr.appendChild(td);
                    }
                }
                tbody.appendChild(tr);
                if (date > daysInMonth) break;
            }
            this.parent.appendChild(tbody);
        }

        // 获取月份数据
        Calendar.prototype.getMonthData = function () {
            const firstDay = new Date(this.year, this.month - 1, 1);
            const lastDay = new Date(this.year, this.month, 0);
            return {
                daysInMonth: lastDay.getDate(),
                startDay: firstDay.getDay()
            };
        }


        let month = new Date().getMonth()
        preButton.addEventListener('click', () => {
            month -= 1
            initCalendars(new Date(new Date().setMonth(month)));
            updateStats();

        })
        nextButton.addEventListener('click', () => {
            month += 1
            initCalendars(new Date(new Date().setMonth(month)));
            updateStats();
        })

        // 初始化日历
        function initCalendars(today = new Date()) {

            const year = today.getFullYear();
            const month = today.getMonth();
            monthTitle.textContent = `${year}年${monthNames[month]}`;
            new Calendar(year, month + 1, document.getElementById("calendar"));
        }

        // 初始化
        initTheme();
        initCalendars();
        updateStats();
    </script>
</body>

</html>